#pragma once
#include <core/types.h>
#include <core/list.h>


// fixme
#define AF_INET     0

#define SOCK_DGRAM  0
#define SOCK_STREAM 0


#define CPU_TO_BE16(val)	 (((val) >> 8) | (((val) & 0xff) << 8))
#define BE16_TO_CPU(val)	 (((val) >> 8) | (((val) & 0xff) << 8))


#define PROT_ICMP 1
#define PROT_IGMP 2
#define PROT_TCP  6
#define PROT_UDP  17
#define PROT_OSPF 89


#define ETH_TYPE_IP   CPU_TO_BE16(0x0800)
#define ETH_TYPE_ARP  CPU_TO_BE16(0x0806)
#define ETH_TYPE_RARP CPU_TO_BE16(0x0835)


#define IPV4_STR_LEN    16
#define IPV4_ADDR_LEN   4
#define MAC_ADDR_LEN    6

#define ETH_HDR_LEN     14
#define ARP_PKT_LEN     28    
#define IP_HDR_LEN      20

#define UDP_HDR_LEN     8
#define MAX_ETH_LEN     (1500 + ETH_HDR_LEN)
#define MIN_ETH_LEN     46

// ping
#define PING_PACKET_LENGTH		64
#define PING_MAX_TIMES    		3
#define PING_DEFUALT_PID   		1

// std ports:
#define STD_PORT_TFTP   69

#define MKIP(a, b, c, d) ((d << 24) | (c << 16) | (b << 8) | a)

enum EtherSpeed
{
	ETHER_SPEED_UNKNOW,
	ETHER_SPEED_10M_HD,
	ETHER_SPEED_10M_FD,
	ETHER_SPEED_100M_HD,
	ETHER_SPEED_100M_FD,
	ETHER_SPEED_1000M_HD,
	ETHER_SPEED_1000M_FD,
};


struct Socket;
struct sockaddr;

struct SocketBuffer
{
	BYTE   *pSkbHead;
	BYTE   *pSkbData;
	//BYTE   *pSkbTail;
	UINT16 wSkbSize;

	struct ListNode node;
	struct Socket *pSock;
};


//
struct EtherHeader
{
	BYTE pbDesMac[MAC_ADDR_LEN];
	BYTE pbSrcMac[MAC_ADDR_LEN];
	UINT16 wFrameType;
};

//
#define ARP_OP_REQ  CPU_TO_BE16(1)
#define ARP_OP_REP  CPU_TO_BE16(2)

struct ArpPacket 
{
	UINT16   wHardType;
	UINT16   wProtType;
	BYTE     bHardSize;
	BYTE     bProtSize;
	UINT16   wArpOpCode;
	BYTE     pbSrcMac[MAC_ADDR_LEN];
	BYTE     pbSrcIP[IPV4_ADDR_LEN];
	BYTE     pbDesMac[MAC_ADDR_LEN];
	BYTE     pbDesIP[IPV4_ADDR_LEN];
} __PACKED__;

//
struct IPHeader
{
	BYTE     bVerHdrLen;
	BYTE     bTOS;
	UINT16   wTotalLen;
	UINT16   wID;
	UINT16   wFlagFrag;
	BYTE     bTimeToLive;
	BYTE     bUpProt;
	UINT16   wChkSum;
	BYTE     pbSrcIP[IPV4_ADDR_LEN];
	BYTE     pbDesIP[IPV4_ADDR_LEN];
};


//
#define ICMP_TYPE_ECHO_REPLY     	0
#define ICMP_TYPE_DEST_UNREACHABLE	3
#define ICMP_TYPE_ECHO_REQUEST   	8

//
struct IcmpPacket
{
	BYTE   type;
	BYTE   code;
	UINT16 wChkSum;
};

//
struct PingPacket
{
	BYTE    type;
	BYTE    code;
	UINT16  wChkSum;
	UINT16  wID;
	UINT16  seqno;
};

//
struct UDPHeader
{
	UINT16 wSrcPort;
	UINT16 wDesPort;
	UINT16 wUdpLen;
	UINT16 wChkSum;
};

//
#define NET_NAME_LEN 16

struct NetDevice
{
	char szName[NET_NAME_LEN];
	struct ListNode ndNetDev;
	BYTE vbMacAddr[MAC_ADDR_LEN];
	//
	int (*SendPacket)(struct NetDevice *, struct SocketBuffer *);
	int (*SetMacAddr)(struct NetDevice *, const BYTE *);
};

struct SocketBuffer *GkSockBuffAlloc(ULONG prot_len, ULONG data_len);

void GkSockBuffFree(struct SocketBuffer * pSockBuff);

///////////
struct sockaddr *gethostaddr(const char *sip);


void GUdpSendPacket(struct SocketBuffer *pSockBuff);

struct SocketBuffer *GUdpRecvPacket(struct Socket *pSock);

void GIpSendPacket(struct SocketBuffer *pSockBuff, BYTE bProtocal);

int IpLayerDeliver(struct SocketBuffer *pSockBuff);

void ARPSend(const BYTE nip[], const BYTE mac[], UINT16 arpop);


///////////////////////////////////

typedef ULONG socklen_t;

struct sockaddr {
	BYTE  pbDesIP[4];
	BYTE  pbDesMac[6];

	UINT16 wDesPort;
	UINT16 wSrcPort;
};


struct Socket {
	struct ListNode quSend, quRecv;
	struct sockaddr addr;
};


int socket(int domain, int type, int protocol);

struct sockaddr *getaddr(UINT32 ip);

int connect(int fd, const struct sockaddr *addr, socklen_t len);

long send(int fd, const void *buf, ULONG n);

long recv(int fd, void *buf, ULONG n);

int close(int fd);


#define NFS_PATH_LEN   256

struct NetConf
{
	UINT32  dwLocalIP;
	UINT32  dwNetMask;
	BYTE    vbLocalMac[MAC_ADDR_LEN];
	UINT32  dwTftpSvrIP;
};


int GuNetGetIP(void *pNetCtrl, UINT32 *pdwIpAddr);

int GuNetSetIP(void *pNetCtrl, UINT32 dwIpAddr);

int GuNetGetMask(void *pNetCtrl, UINT32 *pdwMask);

int GuNetSetMask(void *pNetCtrl, UINT32 dwMask);

int GuNetGetTftpSvr(UINT32 *pdwIpAddr);

int GuNetSetTftpSvr(UINT32 dwIpAddr);

int GuNetGetNfsSvr(UINT32 *pdwIpAddr, 	char szNfsPath[NFS_PATH_LEN]);

int GuNetSetNfsSvr(UINT32 dwIpAddr, const char szNfsPath[NFS_PATH_LEN]);

int GuNetGetMac(void *pNetCtrl, BYTE pbMAC[MAC_ADDR_LEN]);

int GuNetSetMac(void *pNetCtrl, const BYTE pbMAC[MAC_ADDR_LEN]);

int GuStrToIp(BYTE pbIpAddr[4], const char pchIpAddr[IPV4_STR_LEN]);

int GuIpToStr(char pchIpAddr[IPV4_STR_LEN], const UINT32 dwIpAddr);

UINT16 GuNetCheckSum(void *pBuff, ULONG nLen);

struct NetDevice *GkNetDevNew(void);

int GkNetDevRegister(struct NetDevice *pNetDev);

